﻿namespace HZY.Framework.Core.BrowserInfo;

/// <summary>
/// 客户端系统信息 工具类
/// </summary>
public static class OSUtils
{
    public static string ParseOperatingSystem(string userAgentString)
    {
        var version = string.Empty;
        var os = OS.UNKNOWN;
        if (string.IsNullOrWhiteSpace(userAgentString))
        {
            return os.Name;
        }

        if (userAgentString.Contains("iPhone") || userAgentString.Contains("iPod") || userAgentString.Contains("iPad"))
        {
            os = OS.IOS;
            version = GetVersion(userAgentString, os)?.Replace("_", ".") ?? "2";
        }
        else if (userAgentString.Contains("Android"))
        {
            os = OS.ANDROID;
            var vs = GetVersion(userAgentString, os)?.Split('.');
            version = vs?.Length == 1 ? vs[0] : vs?.Length > 1 ? vs[0] + "." + vs[1] : "";
        }
        else if (userAgentString.Contains("Mac OS X"))
        {
            os = OS.MAC;
            version = GetVersion(userAgentString, os)?.Replace("_", ".");
        }
        else if (userAgentString.Contains("Win", StringComparison.Ordinal))
        {
            os = ParseWindowsOS(userAgentString, out version);
        }
        else if (userAgentString.Contains("RIM Tablet OS"))
        {
            os = OS.BBT;
            version = GetVersion(userAgentString, os);
        }
        else if (userAgentString.Contains("BB10"))
        {
            os = OS.BB10;
            version = GetVersion(userAgentString, os);
        }
        else if (userAgentString.Contains("Linux"))
        {
            os = OS.LINUX;
            version = userAgentString.Contains("Ubuntu") ? "Ubuntu" : userAgentString.Contains("UOS") ? "UOS" : "";
        }
        else
        {
            os = OS.UNKNOWN;
        }

        return $"{os.Name} {version}";
    }

    private static OS ParseWindowsOS(string userAgentString, out string version)
    {
        var match = Regex.Match(userAgentString, OS.WIN.Regex);

        if (!match.Success)
        {
            version = string.Empty;
            return OS.WINNT;
        }

        var groups = match.Groups[0].Value.Split(OS.WIN.Separator);

        if (groups.Length == 1)
        {
            version = groups[0].Substring(3);
            return OS.WIN;
        }

        if (groups.Length <= 1)
        {
            version = string.Empty;
            return OS.WINNT;
        }

        var osVersion = groups[1];

        switch (osVersion)
        {
            case "NT":
                version = groups.Length > 2 ? groups[2] : string.Empty;
                return ParseNTVersion(version);
            case "9x":
                version = "9x";
                return OS.WINME;
            case "CE":
                version = string.Empty;
                return OS.WINCE;
            case "Ph":
                version = GetVersion(userAgentString, OS.WINPHONE);
                return OS.WINPHONE;
            default:
                version = osVersion;
                return OS.WIN;
        }
    }

    private static OS ParseNTVersion(string version)
    {
        switch (version)
        {
            case "5.0":
                return OS.WIN2000;
            case "5.1":
                return OS.WINXP;
            case "5.2":
                return OS.WIN2003;
            case "6.0":
                return OS.WINVISTA;
            case "6.1":
                return OS.WIN7;
            case "6.2":
                return OS.WIN8;
            case "6.3":
                return OS.WIN8_1;
            case "10.0":
                return OS.WIN10;
            default:
                return OS.WINNT;
        }
    }

    private static string GetVersion(string userAgentString, OS ose)
    {
        var version = string.Empty;
        var match = Regex.Match(userAgentString, ose.Regex);
        if (match.Success)
        {
            var gs = match.Groups[0].Value.Split(ose.Separator);
            version = gs[^1];
        }
        return version;
    }
}

public class OS
{
    public static readonly OS WIN = new OS("Windows", "Win(?:dows )?([^do]{2})\\s?(\\d+\\.\\d+)?", " ", "PC");
    public static readonly OS WINNT = new OS("Windows NT", "PC");
    public static readonly OS WIN2000 = new OS("Windows 2000", "PC");
    public static readonly OS WINXP = new OS("Windows XP", "PC");
    public static readonly OS WIN2003 = new OS("Windows Server 2003", "PC");
    public static readonly OS WINVISTA = new OS("Windows Vista", "PC");
    public static readonly OS WIN7 = new OS("Windows 7", "PC");
    public static readonly OS WIN8 = new OS("Windows 8", "PC");
    public static readonly OS WIN8_1 = new OS("Windows 8.1", "PC");
    public static readonly OS WIN10 = new OS("Windows 10", "PC");
    public static readonly OS WINME = new OS("Windows ME", "PC");
    public static readonly OS WINCE = new OS("Windows CE", "MOBILE");
    public static readonly OS WINPHONE = new OS("Windows Phone", "Windows Phone OS (\\d+\\.\\d+)", " ", "MOBILE");
    public static readonly OS MAC = new OS("Mac OS X", "Mac OS X (\\d+_\\d+_\\d+)?(\\d+\\.\\d+\\.\\d+)?(\\d+\\.\\d+)?", " ", "PC");
    public static readonly OS IOS = new OS("iOS", "CPU (?:iPhone )?OS (\\d+_\\d+(_\\d+)?)", " ", "MOBILE");
    public static readonly OS ANDROID = new OS("Android", "Android \\d+(\\.\\d+)?(\\.\\d+)?", " ", "MOBILE");
    public static readonly OS LINUX = new OS("Linux", "PC");
    public static readonly OS BB10 = new OS("BlackBerry 10 OS", "Version\\/\\d+\\.\\d+\\.\\d+\\.\\d+", "/", "MOBILE");
    public static readonly OS BBT = new OS("BlackBerry Tablet OS", "RIM Tablet OS \\d+\\.\\d+\\.\\d+", " ", "MOBILE");
    public static readonly OS UNKNOWN = new OS("Other", "");

    public string Name { get; set; }
    public string Regex { get; set; }
    public string Separator { get; set; }
    public string Type { get; set; }

    public OS(string name, string type) : this(name, "", "", type)
    {
    }

    public OS(string name, string regex, string separator, string type)
    {
        Name = name;
        Regex = regex;
        Separator = separator;
        Type = type;
    }
}
